#ifndef TIME_UTIL_H_
#define TIME_UTIL_H_

#include "data_define/type_define.h"
#include "CommonInterface.h"
#include <math.h>

#ifdef _linux_
#include <sys/time.h>
#endif

#include "util.h"

#define SECOND_LEVEL 0
#define MILLISECOND_LEVEL 3
#define MICROSECOND_LEVEL 6
#define NANOSECOND_LEVEL  9



// define the class for calculate the time spending.
#ifndef _linux_
// Windows version.
class tClockTickCount
{
	LARGE_INTEGER Freq;		// frequence of current system.
	bool bHighResClock;		// whether the system provide high res clock.

public:
	tClockTickCount();

	//---------------------------------------------------------------
	// give the interval time between given tickcount and now time.
	//---------------------------------------------------------------
	// Parameters:
	//     tickcount : The tick count to be compared with current tick.
	//     level     : Specify the result format.
	//                 SECOND_LEVEL : Result is measured by second.
	//                 MILLISECOND_LEVEL: Result is measured by millsecond.
	//                 NANOSECOND_LEVEL : Result is measured by nanosecond.
	// Reture Value:
	//     return the gap between now time and given tickcount, measured
	//     by second, millisecond or nanosecond, regarded by level.
	//---------------------------------------------------------------
	INT64 DiffTickCount(UINT64 tickcount, int level);
	//---------------------------------------------------------------


	//---------------------------------------------------------------
	// get now time tickcount.
	//---------------------------------------------------------------
	UINT64 GetTickCount();
	//---------------------------------------------------------------

	//---------------------------------------------------------------
	// Get tick count of specified time.
	//---------------------------------------------------------------
	UINT64 GetTimeTickCount(int millisecond);

	//---------------------------------------------------------------
	// check whether this class use high res clock.
	//---------------------------------------------------------------
	bool IsHighRes();
	//---------------------------------------------------------------
};

///////////////////////////////////////////
// tClockTickCount inline function define.
///////////////////////////////////////////

inline tClockTickCount::tClockTickCount()
{
	QueryPerformanceFrequency(&Freq);
	if (Freq.QuadPart == 0)
		bHighResClock = false;
	else
		bHighResClock = true;
}

// give the interval time between given tickcount and now time.
inline INT64 tClockTickCount::DiffTickCount(UINT64 tickcount, int level)
{
	if (bHighResClock)
	{
		LARGE_INTEGER now;
		QueryPerformanceCounter(&now);
		INT64 diff = now.QuadPart - tickcount;
		return static_cast<INT64>((diff * pow((double)10,level) / Freq.QuadPart));
	}
	else
	{
		UINT64 diff = ::GetTickCount() - tickcount;
		return (INT64)((diff * pow((double)10,level / 1000)));
	}
}

// get now time tickcount.
inline UINT64 tClockTickCount::GetTickCount()
{
	if (bHighResClock)
	{
		LARGE_INTEGER v;
		QueryPerformanceCounter(&v);
		return v.QuadPart;
	}
	else
	{
		return ::GetTickCount();
	}
}

inline UINT64 tClockTickCount::GetTimeTickCount(int millisecond)
{
	UINT64 ms = millisecond;
	if (bHighResClock)
	{
		return ms * Freq.QuadPart / 1000;
	}
	else
	{
		return ms;
	}
}

// check whether this class use high res clock.
inline bool tClockTickCount::IsHighRes()
{
	return bHighResClock;
}

#else

class tClockTickCount
{
public:
	INT64 DiffTickCount(UINT64 tickcount, int level)  
		//0->second; 3->millsec; 6->microsec; 9->nanosec. 
	{
		timeval tv;
		gettimeofday(&tv, NULL);
		UINT64 CurTime = tv.tv_sec * 1000 + tv.tv_usec/1000;
		INT64 diff = CurTime - tickcount;
		return(INT64)(diff * pow((double)10,level) / 1000);
	}
	UINT64 GetTickCount()
	{
		timeval tv;
		gettimeofday(&tv, NULL);
		UINT64 CurTime = tv.tv_sec * 1000 + tv.tv_usec/1000;
		return CurTime;
	}
	bool IsHighRes()
	{
		return true;
	}
};

#endif

//define the timer setting.
struct tTimerItem
{
	unsigned int TimerID;		// ID of this timer.
#ifndef _linux_
	DWORD duetime;				// how long to to count.
#else
	UINT64 duetime;                     // duetime in millisecond.
#endif
	IMsgNotify * pNotify;		// Notify interface.
	int interval;				// interval time.
	bool bRepeat;				// Whether to repeat.

	long Data;

	tTimerItem():TimerID(0),duetime(0),pNotify(NULL),interval(0), 
		bRepeat(false), Data(0)
	{
	}
	bool operator== (const tTimerItem& rti)
	{
		return (rti.TimerID == TimerID);
	}
};

// define the timer.
class tTimer
{
protected:
	unsigned int TimerCount;			// Number of timers.

#ifndef _linux_
	HANDLE hAccessMutex;				// Lock for access(windows).
#else
	tMutex mutex;						// Lock for access(linux).
#endif

	std::deque<tTimerItem> Items;		// Place for each tTimerItem.

	volatile bool bStopSignal;					// signal to stop thread.

#ifndef _linux_
	HANDLE hThread;						// timer thread handle.
	static unsigned int __stdcall Thread(void * param);	// timer thread.

#else
	pthread_t thread_id;				// timer thread id.
	static void* Thread(void *param);	// timer thread.
#endif

public:
	tTimer();
	~tTimer();

	//---------------------------------------------------------------
	// Set a timer item to timer.
	// Parameters:
	//     ms     : How long the timer goes.
	//     notify : Interface to notify the time is up.
	// Return Value:
	//     Return the TimerID of this new timer.
	//---------------------------------------------------------------
	unsigned int SetTimer(DWORD ms, IMsgNotify * notify, bool bRepeat = false,
		long Data = 0);
	//---------------------------------------------------------------

	//---------------------------------------------------------------
	// cancel a timer item in timer.
	// Parameters:
	//     TimerID : The timer id want to cancel.
	//---------------------------------------------------------------
	void CancelTimer(unsigned int TimerID);
	//---------------------------------------------------------------

	//---------------------------------------------------------------
	// Restart the timer.
	//---------------------------------------------------------------
	void ReStartTimer(unsigned int TimerID);
	//---------------------------------------------------------------

	//---------------------------------------------------------------
	// Start the timer thread.
	//---------------------------------------------------------------
	void Start();

	//---------------------------------------------------------------
	// Stop the timer thread.
	//---------------------------------------------------------------
	void Stop();
};

#endif
